<!DOCTYPE html>
<html>
<head>
    

    

    



    <meta charset="utf-8">
    
    
    
    <title>flask使用总结2 | Cucy的博客</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    
    <meta name="theme-color" content="#3F51B5">
    
    
    <meta name="keywords" content="flask">
    <meta name="description" content="[toc]
User Authenticationexample
from werkzeug.security import generate_password_hash, check_password_hashclass User(db.Model):    # ...     password_hash = db.Column(db.String(128))    @property    d">
<meta property="og:type" content="article">
<meta property="og:title" content="flask使用总结2">
<meta property="og:url" content="http://zhourudong.cn/2018/04/18/55-flask使用总结2/index.html">
<meta property="og:site_name" content="Cucy的博客">
<meta property="og:description" content="[toc]
User Authenticationexample
from werkzeug.security import generate_password_hash, check_password_hashclass User(db.Model):    # ...     password_hash = db.Column(db.String(128))    @property    d">
<meta property="og:updated_time" content="2019-02-22T05:28:07.839Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="flask使用总结2">
<meta name="twitter:description" content="[toc]
User Authenticationexample
from werkzeug.security import generate_password_hash, check_password_hashclass User(db.Model):    # ...     password_hash = db.Column(db.String(128))    @property    d">
    
        <link rel="alternate" type="application/atom+xml" title="Cucy的博客" href="/atom.xml">
    
    <link rel="shortcut icon" href="/favicon.ico">
    <link rel="stylesheet" href="/css/style.css?v=1.6.13">
    <script>window.lazyScripts=[]</script>

    <!-- custom head -->
    

</head>

<body>
    <div id="loading" class="active"></div>

    <aside id="menu" class="hide" >
  <div class="inner flex-row-vertical">
    <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="menu-off">
        <i class="icon icon-lg icon-close"></i>
    </a>
    <div class="brand-wrap" style="background-image:url(/img/brand.jpg)">
      <div class="brand">
        <a href="/" class="avatar waves-effect waves-circle waves-light">
          <img src="/img/avatar.png">
        </a>
        <hgroup class="introduce">
          <h5 class="nickname">cucy</h5>
          <a href="mailto:292016176@qq.com" title="292016176@qq.com" class="mail">292016176@qq.com</a>
        </hgroup>
      </div>
    </div>
    <div class="scroll-wrap flex-col">
      <ul class="nav">
        
            <li class="waves-block waves-effect">
              <a href="/"  >
                <i class="icon icon-lg icon-home"></i>
                主页
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="/archives"  >
                <i class="icon icon-lg icon-archives"></i>
                Archives
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="/tags"  >
                <i class="icon icon-lg icon-tags"></i>
                Tags
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="https://github.com/cucy" target="_blank" >
                <i class="icon icon-lg icon-github"></i>
                Github
              </a>
            </li>
        
      </ul>
    </div>
  </div>
</aside>

    <main id="main">
        <header class="top-header" id="header">
    <div class="flex-row">
        <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light on" id="menu-toggle">
          <i class="icon icon-lg icon-navicon"></i>
        </a>
        <div class="flex-col header-title ellipsis">flask使用总结2</div>
        
        <div class="search-wrap" id="search-wrap">
            <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="back">
                <i class="icon icon-lg icon-chevron-left"></i>
            </a>
            <input type="text" id="key" class="search-input" autocomplete="off" placeholder="输入感兴趣的关键字">
            <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="search">
                <i class="icon icon-lg icon-search"></i>
            </a>
        </div>
        
        
        <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="menuShare">
            <i class="icon icon-lg icon-share-alt"></i>
        </a>
        
    </div>
</header>
<header class="content-header post-header">

    <div class="container fade-scale">
        <h1 class="title">flask使用总结2</h1>
        <h5 class="subtitle">
            
                <time datetime="2018-04-18T07:18:32.000Z" itemprop="datePublished" class="page-time">
  2018-04-18
</time>


            
        </h5>
    </div>

    


</header>


<div class="container body-wrap">
    
    <aside class="post-widget">
        <nav class="post-toc-wrap" id="post-toc">
            <h4>TOC</h4>
            <ol class="post-toc"><li class="post-toc-item post-toc-level-1"><a class="post-toc-link" href="#User-Authentication"><span class="post-toc-number">1.</span> <span class="post-toc-text">User Authentication</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#tests-test-user-model-py-Password-hashing-tests"><span class="post-toc-number">1.1.</span> <span class="post-toc-text">tests/test_user_model.py: Password hashing tests</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#app-auth-init-py-Blueprint-creation-1"><span class="post-toc-number">1.2.</span> <span class="post-toc-text">app/auth/init.py: Blueprint creation 1</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#app-auth-views-py-Blueprint-routes-and-view-functions-2"><span class="post-toc-number">1.3.</span> <span class="post-toc-text">app/auth/views.py: Blueprint routes and view functions 2</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#app-init-py-Blueprint-attachment-3"><span class="post-toc-number">1.4.</span> <span class="post-toc-text">app/init.py: Blueprint attachment 3</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#User-Authentication-with-Flask-Login"><span class="post-toc-number">1.5.</span> <span class="post-toc-text">User Authentication with Flask-Login</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#app-models-py-Updates-to-the-User-model-to-support-user-logins-1"><span class="post-toc-number">1.6.</span> <span class="post-toc-text">app/models.py: Updates to the User model to support user logins 1</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#app-init-py-Flask-Login-initialization-2"><span class="post-toc-number">1.7.</span> <span class="post-toc-text">app/init.py: Flask-Login initialization 2</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#app-models-py-User-loader-callback-function-3"><span class="post-toc-number">1.8.</span> <span class="post-toc-text">app/models.py: User loader callback function 3</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#login-required登录装饰器"><span class="post-toc-number">1.9.</span> <span class="post-toc-text">login_required登录装饰器</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#app-auth-forms-py-Login-form-4-登录表单"><span class="post-toc-number">1.10.</span> <span class="post-toc-text">app/auth/forms.py: Login form 4 登录表单</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#app-templates-base-html-Sign-In-and-Sign-Out-navigation-bar-links-退出登录连接"><span class="post-toc-number">1.11.</span> <span class="post-toc-text">app/templates/base.html: Sign In and Sign Out navigation bar links 退出登录连接</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#app-auth-views-py-Sign-In-route-用户登录view"><span class="post-toc-number">1.12.</span> <span class="post-toc-text">app/auth/views.py: Sign In route 用户登录view</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#app-templates-auth-login-html-Render-login-form-登录表单-4"><span class="post-toc-number">1.13.</span> <span class="post-toc-text">app/templates/auth/login.html: Render login form 登录表单 4</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#app-auth-views-py-Sign-Out-route-用户登出-1"><span class="post-toc-number">1.14.</span> <span class="post-toc-text">app/auth/views.py: Sign Out route 用户登出 1</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#app-templates-index-html-Greet-the-logged-in-user-2"><span class="post-toc-number">1.15.</span> <span class="post-toc-text">app/templates/index.html: Greet the logged-in user 2</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#app-auth-forms-py-User-registration-form-新用户注册"><span class="post-toc-number">1.16.</span> <span class="post-toc-text">app/auth/forms.py: User registration form 新用户注册</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#app-auth-forms-py-User-registration-form-1"><span class="post-toc-number">1.17.</span> <span class="post-toc-text">app/auth/forms.py: User registration form 1</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#app-auth-views-py-User-registration-route-注册新用户"><span class="post-toc-number">1.18.</span> <span class="post-toc-text">app/auth/views.py: User registration route 注册新用户</span></a></li></ol></li><li class="post-toc-item post-toc-level-1"><a class="post-toc-link" href="#用户权限"><span class="post-toc-number">2.</span> <span class="post-toc-text">用户权限</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#app-models-py-Role-permissions-1"><span class="post-toc-number">2.1.</span> <span class="post-toc-text">app/models.py: Role permissions 1</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#app-models-py-Permission-constants-2"><span class="post-toc-number">2.2.</span> <span class="post-toc-text">app/models.py: Permission constants 2</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#app-models-py-Permission-management-in-the-Role-model-3"><span class="post-toc-number">2.3.</span> <span class="post-toc-text">app/models.py: Permission management in the Role model 3</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#app-models-py-Create-roles-in-the-database-3"><span class="post-toc-number">2.4.</span> <span class="post-toc-text">app/models.py: Create roles in the database 3</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#app-models-py-Define-a-default-role-for-users-权限分配"><span class="post-toc-number">2.5.</span> <span class="post-toc-text">app/models.py: Define a default role for users 权限分配</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#app-models-py-Evaluate-whether-a-user-has-a-given-permission-权限检查"><span class="post-toc-number">2.6.</span> <span class="post-toc-text">app/models.py: Evaluate whether a user has a given permission 权限检查</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#权限检查装饰器"><span class="post-toc-number">2.7.</span> <span class="post-toc-text">权限检查装饰器</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#使用权限装饰器"><span class="post-toc-number">2.8.</span> <span class="post-toc-text">使用权限装饰器</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#将权限检查添加到-全局上下文中"><span class="post-toc-number">2.9.</span> <span class="post-toc-text">将权限检查添加到 全局上下文中</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#测试"><span class="post-toc-number">2.10.</span> <span class="post-toc-text">测试</span></a></li></ol></li></ol>
        </nav>
    </aside>
    
<article id="post-55-flask使用总结2"
  class="post-article article-type-post fade" itemprop="blogPost">

    <div class="post-card">
        <h1 class="post-card-title">flask使用总结2</h1>
        <div class="post-meta">
            <time class="post-time" title="2018-04-18 15:18:32" datetime="2018-04-18T07:18:32.000Z"  itemprop="datePublished">2018-04-18</time>

            


            
<span id="busuanzi_container_page_pv" title="文章总阅读量" style='display:none'>
    <i class="icon icon-eye icon-pr"></i><span id="busuanzi_value_page_pv"></span>
</span>


        </div>
        <div class="post-content" id="post-content" itemprop="postContent">
            <p>[toc]</p>
<h1 id="User-Authentication"><a href="#User-Authentication" class="headerlink" title="User Authentication"></a>User Authentication</h1><p><code>example</code></p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> werkzeug.security <span class="keyword">import</span> generate_password_hash, check_password_hash</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">User</span><span class="params">(db.Model)</span>:</span></span><br><span class="line">    <span class="comment"># ... </span></span><br><span class="line">    password_hash = db.Column(db.String(<span class="number">128</span>))</span><br><span class="line"></span><br><span class="line"><span class="meta">    @property</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">password</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">raise</span> AttributeError(<span class="string">'password is not a readable attribute'</span>)</span><br><span class="line"></span><br><span class="line"><span class="meta">    @password.setter</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">password</span><span class="params">(self, password)</span>:</span></span><br><span class="line">        self.password_hash = generate_password_hash(password)</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">verify_password</span><span class="params">(self, password)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> check_password_hash(self.password_hash, password)</span><br></pre></td></tr></table></figure>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line">(venv) $ flask shell</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>u = User()</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>u.password = <span class="string">'cat'</span></span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>u.password</span><br><span class="line">Traceback (most recent call last):  </span><br><span class="line">  File <span class="string">"&lt;console&gt;"</span>, line <span class="number">1</span>, <span class="keyword">in</span> &lt;module&gt;</span><br><span class="line">   File <span class="string">"/home/flask/flasky/app/models.py"</span>, line <span class="number">24</span>, <span class="keyword">in</span> password</span><br><span class="line">       <span class="keyword">raise</span> AttributeError(<span class="string">'password is not a readable attribute'</span>)AttributeError: password <span class="keyword">is</span> <span class="keyword">not</span> a readable attribute</span><br><span class="line"> &gt;&gt;&gt; u.password_hash</span><br><span class="line"> <span class="string">'pbkdf2:sha256:50000$moHwFH1B$ef1574909f9c549285e8547cad181c5e0213cfa44a4aba4349fa830aa1fd227f'</span></span><br><span class="line"> &gt;&gt;&gt; u.verify_password(<span class="string">'cat'</span>)</span><br><span class="line"> <span class="keyword">True</span></span><br><span class="line"> &gt;&gt;&gt; u.verify_password(<span class="string">'dog'</span>)</span><br><span class="line"> <span class="keyword">False</span></span><br><span class="line"> &gt;&gt;&gt; u2 = User()</span><br><span class="line"> &gt;&gt;&gt; u2.password = <span class="string">'cat'</span></span><br><span class="line"> &gt;&gt;&gt; u2.password_hash</span><br><span class="line"> <span class="string">'pbkdf2:sha256:50000$Pfz0m0KU$27be930b7f0e0119d38e8d8a62f7f5e75c0a7db61ae16709bcaa6cfd60c44b74'</span></span><br></pre></td></tr></table></figure>
<h2 id="tests-test-user-model-py-Password-hashing-tests"><a href="#tests-test-user-model-py-Password-hashing-tests" class="headerlink" title="tests/test_user_model.py: Password hashing tests"></a>tests/test_user_model.py: Password hashing tests</h2><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> unittest</span><br><span class="line"><span class="keyword">from</span> app <span class="keyword">import</span> create_app, db</span><br><span class="line"><span class="keyword">from</span> app.models <span class="keyword">import</span> User</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">UserModelTestCase</span><span class="params">(unittest.TestCase)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">setUp</span><span class="params">(self)</span>:</span></span><br><span class="line">        self.app = create_app(<span class="string">'testing'</span>)</span><br><span class="line">        self.app_context = self.app.app_context()</span><br><span class="line">        self.app_context.push()</span><br><span class="line">        db.create_all()</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">tearDown</span><span class="params">(self)</span>:</span></span><br><span class="line">        db.session.remove()</span><br><span class="line">        db.drop_all()</span><br><span class="line">        self.app_context.pop()</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">test_password_setter</span><span class="params">(self)</span>:</span></span><br><span class="line">        u = User(password=<span class="string">'cat'</span>)</span><br><span class="line">        self.assertTrue(u.password_hash <span class="keyword">is</span> <span class="keyword">not</span> <span class="keyword">None</span>)</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">test_no_password_getter</span><span class="params">(self)</span>:</span></span><br><span class="line">        u = User(password=<span class="string">'cat'</span>)</span><br><span class="line">        <span class="keyword">with</span> self.assertRaises(AttributeError):</span><br><span class="line">            u.password</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">test_password_verification</span><span class="params">(self)</span>:</span></span><br><span class="line">        u = User(password=<span class="string">'cat'</span>)</span><br><span class="line">        self.assertTrue(u.verify_password(<span class="string">'cat'</span>))</span><br><span class="line">        self.assertFalse(u.verify_password(<span class="string">'dog'</span>))</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">test_password_salts_are_random</span><span class="params">(self)</span>:</span></span><br><span class="line">        u = User(password=<span class="string">'cat'</span>)</span><br><span class="line">        u2 = User(password=<span class="string">'cat'</span>)</span><br><span class="line">        self.assertTrue(u.password_hash != u2.password_hash)</span><br></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">(venv) $ flask <span class="built_in">test</span></span><br><span class="line">test_app_exists (test_basics.BasicsTestCase) ... ok</span><br><span class="line">test_app_is_testing (test_basics.BasicsTestCase) ... ok</span><br><span class="line">test_no_password_getter (test_user_model.UserModelTestCase) ... ok</span><br><span class="line">test_password_salts_are_random (test_user_model.UserModelTestCase) ... ok</span><br><span class="line">test_password_setter (test_user_model.UserModelTestCase) ... ok</span><br><span class="line">test_password_verification (test_user_model.UserModelTestCase) ... ok</span><br><span class="line"></span><br><span class="line">----------------------------------------------------------------------</span><br><span class="line">Ran 6 tests <span class="keyword">in</span> 0.393s</span><br><span class="line"></span><br><span class="line">OK</span><br></pre></td></tr></table></figure>
<h2 id="app-auth-init-py-Blueprint-creation-1"><a href="#app-auth-init-py-Blueprint-creation-1" class="headerlink" title="app/auth/init.py: Blueprint creation 1"></a>app/auth/<strong>init</strong>.py: Blueprint creation 1</h2><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> flask <span class="keyword">import</span> Blueprint</span><br><span class="line"></span><br><span class="line">auth = Blueprint(<span class="string">'auth'</span>, __name__)</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> . <span class="keyword">import</span> views</span><br></pre></td></tr></table></figure>
<h2 id="app-auth-views-py-Blueprint-routes-and-view-functions-2"><a href="#app-auth-views-py-Blueprint-routes-and-view-functions-2" class="headerlink" title="app/auth/views.py: Blueprint routes and view functions 2"></a>app/auth/views.py: Blueprint routes and view functions 2</h2><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> flask <span class="keyword">import</span> render_template</span><br><span class="line"><span class="keyword">from</span> . <span class="keyword">import</span> auth</span><br><span class="line"></span><br><span class="line"><span class="meta">@auth.route('/login')</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">login</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">return</span> render_template(<span class="string">'auth/login.html'</span>)</span><br></pre></td></tr></table></figure>
<h2 id="app-init-py-Blueprint-attachment-3"><a href="#app-init-py-Blueprint-attachment-3" class="headerlink" title="app/init.py: Blueprint attachment 3"></a>app/<strong>init</strong>.py: Blueprint attachment 3</h2><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">create_app</span><span class="params">(config_name)</span>:</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># ...    </span></span><br><span class="line">    <span class="keyword">from</span> .auth <span class="keyword">import</span> auth <span class="keyword">as</span> auth_blueprint</span><br><span class="line">    app.register_blueprint(auth_blueprint, url_prefix=<span class="string">'/auth'</span>)</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> app</span><br></pre></td></tr></table></figure>
<h2 id="User-Authentication-with-Flask-Login"><a href="#User-Authentication-with-Flask-Login" class="headerlink" title="User Authentication with Flask-Login"></a>User Authentication with Flask-Login</h2><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">(venv) $ pip install flask-login</span><br></pre></td></tr></table></figure>
<h2 id="app-models-py-Updates-to-the-User-model-to-support-user-logins-1"><a href="#app-models-py-Updates-to-the-User-model-to-support-user-logins-1" class="headerlink" title="app/models.py: Updates to the User model to support user logins 1"></a>app/models.py: Updates to the User model to support user logins 1</h2><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> werkzeug.security <span class="keyword">import</span> generate_password_hash, check_password_hash</span><br><span class="line"><span class="keyword">from</span> itsdangerous <span class="keyword">import</span> TimedJSONWebSignatureSerializer <span class="keyword">as</span> Serializer</span><br><span class="line"><span class="keyword">from</span> flask <span class="keyword">import</span> current_app</span><br><span class="line"><span class="keyword">from</span> flask_login <span class="keyword">import</span> UserMixin, AnonymousUserMixin</span><br><span class="line"><span class="keyword">from</span> . <span class="keyword">import</span> db, login_manager</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Permission</span>:</span></span><br><span class="line">    FOLLOW = <span class="number">1</span></span><br><span class="line">    COMMENT = <span class="number">2</span></span><br><span class="line">    WRITE = <span class="number">4</span></span><br><span class="line">    MODERATE = <span class="number">8</span></span><br><span class="line">    ADMIN = <span class="number">16</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Role</span><span class="params">(db.Model)</span>:</span></span><br><span class="line">    __tablename__ = <span class="string">'roles'</span></span><br><span class="line">    id = db.Column(db.Integer, primary_key=<span class="keyword">True</span>)</span><br><span class="line">    name = db.Column(db.String(<span class="number">64</span>), unique=<span class="keyword">True</span>)</span><br><span class="line">    default = db.Column(db.Boolean, default=<span class="keyword">False</span>, index=<span class="keyword">True</span>)</span><br><span class="line">    permissions = db.Column(db.Integer)</span><br><span class="line">    users = db.relationship(<span class="string">'User'</span>, backref=<span class="string">'role'</span>, lazy=<span class="string">'dynamic'</span>)</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, **kwargs)</span>:</span></span><br><span class="line">        super(Role, self).__init__(**kwargs)</span><br><span class="line">        <span class="keyword">if</span> self.permissions <span class="keyword">is</span> <span class="keyword">None</span>:</span><br><span class="line">            self.permissions = <span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="meta">    @staticmethod</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">insert_roles</span><span class="params">()</span>:</span></span><br><span class="line">        roles = &#123;</span><br><span class="line">            <span class="string">'User'</span>: [Permission.FOLLOW, Permission.COMMENT, Permission.WRITE],</span><br><span class="line">            <span class="string">'Moderator'</span>: [Permission.FOLLOW, Permission.COMMENT,</span><br><span class="line">                          Permission.WRITE, Permission.MODERATE],</span><br><span class="line">            <span class="string">'Administrator'</span>: [Permission.FOLLOW, Permission.COMMENT,</span><br><span class="line">                              Permission.WRITE, Permission.MODERATE,</span><br><span class="line">                              Permission.ADMIN],</span><br><span class="line">        &#125;</span><br><span class="line">        default_role = <span class="string">'User'</span></span><br><span class="line">        <span class="keyword">for</span> r <span class="keyword">in</span> roles:</span><br><span class="line">            role = Role.query.filter_by(name=r).first()</span><br><span class="line">            <span class="keyword">if</span> role <span class="keyword">is</span> <span class="keyword">None</span>:</span><br><span class="line">                role = Role(name=r)</span><br><span class="line">            role.reset_permissions()</span><br><span class="line">            <span class="keyword">for</span> perm <span class="keyword">in</span> roles[r]:</span><br><span class="line">                role.add_permission(perm)</span><br><span class="line">            role.default = (role.name == default_role)</span><br><span class="line">            db.session.add(role)</span><br><span class="line">        db.session.commit()</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">add_permission</span><span class="params">(self, perm)</span>:</span></span><br><span class="line">        <span class="keyword">if</span> <span class="keyword">not</span> self.has_permission(perm):</span><br><span class="line">            self.permissions += perm</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">remove_permission</span><span class="params">(self, perm)</span>:</span></span><br><span class="line">        <span class="keyword">if</span> self.has_permission(perm):</span><br><span class="line">            self.permissions -= perm</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">reset_permissions</span><span class="params">(self)</span>:</span></span><br><span class="line">        self.permissions = <span class="number">0</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">has_permission</span><span class="params">(self, perm)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> self.permissions &amp; perm == perm</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__repr__</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> <span class="string">'&lt;Role %r&gt;'</span> % self.name</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">User</span><span class="params">(UserMixin, db.Model)</span>:</span></span><br><span class="line">    __tablename__ = <span class="string">'users'</span></span><br><span class="line">    id = db.Column(db.Integer, primary_key=<span class="keyword">True</span>)</span><br><span class="line">    email = db.Column(db.String(<span class="number">64</span>), unique=<span class="keyword">True</span>, index=<span class="keyword">True</span>)</span><br><span class="line">    username = db.Column(db.String(<span class="number">64</span>), unique=<span class="keyword">True</span>, index=<span class="keyword">True</span>)</span><br><span class="line">    role_id = db.Column(db.Integer, db.ForeignKey(<span class="string">'roles.id'</span>))</span><br><span class="line">    password_hash = db.Column(db.String(<span class="number">128</span>))</span><br><span class="line">    confirmed = db.Column(db.Boolean, default=<span class="keyword">False</span>)</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, **kwargs)</span>:</span></span><br><span class="line">        super(User, self).__init__(**kwargs)</span><br><span class="line">        <span class="keyword">if</span> self.role <span class="keyword">is</span> <span class="keyword">None</span>:</span><br><span class="line">            <span class="keyword">if</span> self.email == current_app.config[<span class="string">'FLASKY_ADMIN'</span>]:</span><br><span class="line">                self.role = Role.query.filter_by(name=<span class="string">'Administrator'</span>).first()</span><br><span class="line">            <span class="keyword">if</span> self.role <span class="keyword">is</span> <span class="keyword">None</span>:</span><br><span class="line">                self.role = Role.query.filter_by(default=<span class="keyword">True</span>).first()</span><br><span class="line"></span><br><span class="line"><span class="meta">    @property</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">password</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">raise</span> AttributeError(<span class="string">'password is not a readable attribute'</span>)</span><br><span class="line"></span><br><span class="line"><span class="meta">    @password.setter</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">password</span><span class="params">(self, password)</span>:</span></span><br><span class="line">        self.password_hash = generate_password_hash(password)</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">verify_password</span><span class="params">(self, password)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> check_password_hash(self.password_hash, password)</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">generate_confirmation_token</span><span class="params">(self, expiration=<span class="number">3600</span>)</span>:</span></span><br><span class="line">        s = Serializer(current_app.config[<span class="string">'SECRET_KEY'</span>], expiration)</span><br><span class="line">        <span class="keyword">return</span> s.dumps(&#123;<span class="string">'confirm'</span>: self.id&#125;).decode(<span class="string">'utf-8'</span>)</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">confirm</span><span class="params">(self, token)</span>:</span></span><br><span class="line">        s = Serializer(current_app.config[<span class="string">'SECRET_KEY'</span>])</span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            data = s.loads(token.encode(<span class="string">'utf-8'</span>))</span><br><span class="line">        <span class="keyword">except</span>:</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">False</span></span><br><span class="line">        <span class="keyword">if</span> data.get(<span class="string">'confirm'</span>) != self.id:</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">False</span></span><br><span class="line">        self.confirmed = <span class="keyword">True</span></span><br><span class="line">        db.session.add(self)</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">True</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">generate_reset_token</span><span class="params">(self, expiration=<span class="number">3600</span>)</span>:</span></span><br><span class="line">        s = Serializer(current_app.config[<span class="string">'SECRET_KEY'</span>], expiration)</span><br><span class="line">        <span class="keyword">return</span> s.dumps(&#123;<span class="string">'reset'</span>: self.id&#125;).decode(<span class="string">'utf-8'</span>)</span><br><span class="line"></span><br><span class="line"><span class="meta">    @staticmethod</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">reset_password</span><span class="params">(token, new_password)</span>:</span></span><br><span class="line">        s = Serializer(current_app.config[<span class="string">'SECRET_KEY'</span>])</span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            data = s.loads(token.encode(<span class="string">'utf-8'</span>))</span><br><span class="line">        <span class="keyword">except</span>:</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">False</span></span><br><span class="line">        user = User.query.get(data.get(<span class="string">'reset'</span>))</span><br><span class="line">        <span class="keyword">if</span> user <span class="keyword">is</span> <span class="keyword">None</span>:</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">False</span></span><br><span class="line">        user.password = new_password</span><br><span class="line">        db.session.add(user)</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">True</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">generate_email_change_token</span><span class="params">(self, new_email, expiration=<span class="number">3600</span>)</span>:</span></span><br><span class="line">        s = Serializer(current_app.config[<span class="string">'SECRET_KEY'</span>], expiration)</span><br><span class="line">        <span class="keyword">return</span> s.dumps(</span><br><span class="line">            &#123;<span class="string">'change_email'</span>: self.id, <span class="string">'new_email'</span>: new_email&#125;).decode(<span class="string">'utf-8'</span>)</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">change_email</span><span class="params">(self, token)</span>:</span></span><br><span class="line">        s = Serializer(current_app.config[<span class="string">'SECRET_KEY'</span>])</span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            data = s.loads(token.encode(<span class="string">'utf-8'</span>))</span><br><span class="line">        <span class="keyword">except</span>:</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">False</span></span><br><span class="line">        <span class="keyword">if</span> data.get(<span class="string">'change_email'</span>) != self.id:</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">False</span></span><br><span class="line">        new_email = data.get(<span class="string">'new_email'</span>)</span><br><span class="line">        <span class="keyword">if</span> new_email <span class="keyword">is</span> <span class="keyword">None</span>:</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">False</span></span><br><span class="line">        <span class="keyword">if</span> self.query.filter_by(email=new_email).first() <span class="keyword">is</span> <span class="keyword">not</span> <span class="keyword">None</span>:</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">False</span></span><br><span class="line">        self.email = new_email</span><br><span class="line">        db.session.add(self)</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">True</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">can</span><span class="params">(self, perm)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> self.role <span class="keyword">is</span> <span class="keyword">not</span> <span class="keyword">None</span> <span class="keyword">and</span> self.role.has_permission(perm)</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">is_administrator</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> self.can(Permission.ADMIN)</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__repr__</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> <span class="string">'&lt;User %r&gt;'</span> % self.username</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AnonymousUser</span><span class="params">(AnonymousUserMixin)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">can</span><span class="params">(self, permissions)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">False</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">is_administrator</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">False</span></span><br><span class="line"></span><br><span class="line">login_manager.anonymous_user = AnonymousUser</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">@login_manager.user_loader</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">load_user</span><span class="params">(user_id)</span>:</span></span><br><span class="line">    <span class="keyword">return</span> User.query.get(int(user_id))</span><br></pre></td></tr></table></figure>
<h2 id="app-init-py-Flask-Login-initialization-2"><a href="#app-init-py-Flask-Login-initialization-2" class="headerlink" title="app/init.py: Flask-Login initialization 2"></a>app/<strong>init</strong>.py: Flask-Login initialization 2</h2><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> flask_login <span class="keyword">import</span> LoginManager</span><br><span class="line"></span><br><span class="line">login_manager = LoginManager()</span><br><span class="line">login_manager.login_view = <span class="string">'auth.login'</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">create_app</span><span class="params">(config_name)</span>:</span></span><br><span class="line">    <span class="comment"># ...</span></span><br><span class="line">    login_manager.init_app(app)</span><br><span class="line">    <span class="comment"># ...</span></span><br></pre></td></tr></table></figure>
<h2 id="app-models-py-User-loader-callback-function-3"><a href="#app-models-py-User-loader-callback-function-3" class="headerlink" title="app/models.py: User loader callback function 3"></a>app/models.py: User loader callback function 3</h2><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> . <span class="keyword">import</span> login_manager</span><br><span class="line"></span><br><span class="line"><span class="meta">@login_manager.user_loader</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">load_user</span><span class="params">(user_id)</span>:</span></span><br><span class="line">    <span class="keyword">return</span> User.query.get(int(user_id))</span><br></pre></td></tr></table></figure>
<h2 id="login-required登录装饰器"><a href="#login-required登录装饰器" class="headerlink" title="login_required登录装饰器"></a>login_required登录装饰器</h2><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> flask_login <span class="keyword">import</span> login_required</span><br><span class="line"></span><br><span class="line"><span class="meta">@app.route('/secret')</span></span><br><span class="line"><span class="meta">@login_required</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">secret</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">return</span> <span class="string">'Only authenticated users are allowed!'</span></span><br></pre></td></tr></table></figure>
<h2 id="app-auth-forms-py-Login-form-4-登录表单"><a href="#app-auth-forms-py-Login-form-4-登录表单" class="headerlink" title="app/auth/forms.py: Login form 4 登录表单"></a>app/auth/forms.py: Login form 4 登录表单</h2><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> flask_wtf <span class="keyword">import</span> FlaskForm</span><br><span class="line"><span class="keyword">from</span> wtforms <span class="keyword">import</span> StringField, PasswordField, BooleanField, SubmitField</span><br><span class="line"><span class="keyword">from</span> wtforms.validators <span class="keyword">import</span> DataRequired, Length, Email, Regexp, EqualTo</span><br><span class="line"><span class="keyword">from</span> wtforms <span class="keyword">import</span> ValidationError</span><br><span class="line"><span class="keyword">from</span> ..models <span class="keyword">import</span> User</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">LoginForm</span><span class="params">(FlaskForm)</span>:</span></span><br><span class="line">    email = StringField(<span class="string">'Email'</span>, validators=[DataRequired(), Length(<span class="number">1</span>, <span class="number">64</span>),</span><br><span class="line">                                             Email()])</span><br><span class="line">    password = PasswordField(<span class="string">'Password'</span>, validators=[DataRequired()])</span><br><span class="line">    remember_me = BooleanField(<span class="string">'Keep me logged in'</span>)</span><br><span class="line">    submit = SubmitField(<span class="string">'Log In'</span>)</span><br></pre></td></tr></table></figure>
<h2 id="app-templates-base-html-Sign-In-and-Sign-Out-navigation-bar-links-退出登录连接"><a href="#app-templates-base-html-Sign-In-and-Sign-Out-navigation-bar-links-退出登录连接" class="headerlink" title="app/templates/base.html: Sign In and Sign Out navigation bar links 退出登录连接"></a>app/templates/base.html: Sign In and Sign Out navigation bar links 退出登录连接</h2><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">ul</span> <span class="attr">class</span>=<span class="string">"nav navbar-nav navbar-right"</span>&gt;</span></span><br><span class="line">    &#123;% if current_user.is_authenticated %&#125;</span><br><span class="line">        <span class="tag">&lt;<span class="name">li</span> <span class="attr">class</span>=<span class="string">"dropdown"</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">"#"</span> <span class="attr">class</span>=<span class="string">"dropdown-toggle"</span> <span class="attr">data-toggle</span>=<span class="string">"dropdown"</span>&gt;</span>Account <span class="tag">&lt;<span class="name">b</span> <span class="attr">class</span>=<span class="string">"caret"</span>&gt;</span><span class="tag">&lt;/<span class="name">b</span>&gt;</span><span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">ul</span> <span class="attr">class</span>=<span class="string">"dropdown-menu"</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">li</span>&gt;</span><span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">"&#123;&#123; url_for('auth.change_password') &#125;&#125;"</span>&gt;</span>Change Password<span class="tag">&lt;/<span class="name">a</span>&gt;</span><span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">li</span>&gt;</span><span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">"&#123;&#123; url_for('auth.change_email_request') &#125;&#125;"</span>&gt;</span>Change Email<span class="tag">&lt;/<span class="name">a</span>&gt;</span><span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">li</span>&gt;</span><span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">"&#123;&#123; url_for('auth.logout') &#125;&#125;"</span>&gt;</span>Log Out<span class="tag">&lt;/<span class="name">a</span>&gt;</span><span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    &#123;% else %&#125;</span><br><span class="line">        <span class="tag">&lt;<span class="name">li</span>&gt;</span><span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">"&#123;&#123; url_for('auth.login') &#125;&#125;"</span>&gt;</span>Log In<span class="tag">&lt;/<span class="name">a</span>&gt;</span><span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    &#123;% endif %&#125;</span><br><span class="line"><span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h2 id="app-auth-views-py-Sign-In-route-用户登录view"><a href="#app-auth-views-py-Sign-In-route-用户登录view" class="headerlink" title="app/auth/views.py: Sign In route 用户登录view"></a>app/auth/views.py: Sign In route 用户登录view</h2><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> flask <span class="keyword">import</span> render_template, redirect, request, url_for, flash</span><br><span class="line"><span class="keyword">from</span> flask_login <span class="keyword">import</span> login_user, logout_user, login_required, \</span><br><span class="line">    current_user</span><br><span class="line"><span class="keyword">from</span> . <span class="keyword">import</span> auth</span><br><span class="line"><span class="keyword">from</span> .. <span class="keyword">import</span> db</span><br><span class="line"><span class="keyword">from</span> ..models <span class="keyword">import</span> User</span><br><span class="line"><span class="keyword">from</span> ..email <span class="keyword">import</span> send_email</span><br><span class="line"><span class="keyword">from</span> .forms <span class="keyword">import</span> LoginForm, RegistrationForm, ChangePasswordForm,\</span><br><span class="line">    PasswordResetRequestForm, PasswordResetForm, ChangeEmailForm</span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line"><span class="meta">@auth.route('/login', methods=['GET', 'POST'])</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">login</span><span class="params">()</span>:</span></span><br><span class="line">    form = LoginForm()</span><br><span class="line">    <span class="keyword">if</span> form.validate_on_submit():</span><br><span class="line">        user = User.query.filter_by(email=form.email.data).first()</span><br><span class="line">        <span class="keyword">if</span> user <span class="keyword">is</span> <span class="keyword">not</span> <span class="keyword">None</span> <span class="keyword">and</span> user.verify_password(form.password.data):</span><br><span class="line">            login_user(user, form.remember_me.data)</span><br><span class="line">            next = request.args.get(<span class="string">'next'</span>)</span><br><span class="line">            <span class="keyword">if</span> next <span class="keyword">is</span> <span class="keyword">None</span> <span class="keyword">or</span> <span class="keyword">not</span> next.startswith(<span class="string">'/'</span>):</span><br><span class="line">                next = url_for(<span class="string">'main.index'</span>)</span><br><span class="line">            <span class="keyword">return</span> redirect(next)</span><br><span class="line">        flash(<span class="string">'Invalid username or password.'</span>)</span><br><span class="line">    <span class="keyword">return</span> render_template(<span class="string">'auth/login.html'</span>, form=form)</span><br></pre></td></tr></table></figure>
<h2 id="app-templates-auth-login-html-Render-login-form-登录表单-4"><a href="#app-templates-auth-login-html-Render-login-form-登录表单-4" class="headerlink" title="app/templates/auth/login.html: Render login form 登录表单 4"></a>app/templates/auth/login.html: Render login form 登录表单 4</h2><figure class="highlight html"><table><tr><td class="code"><pre><span class="line">&#123;% extends "base.html" %&#125;</span><br><span class="line">&#123;% import "bootstrap/wtf.html" as wtf %&#125;</span><br><span class="line"></span><br><span class="line">&#123;% block title %&#125;Flasky - Login&#123;% endblock %&#125;</span><br><span class="line"></span><br><span class="line">&#123;% block page_content %&#125;</span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"page-header"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">h1</span>&gt;</span>Login<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"col-md-4"</span>&gt;</span></span><br><span class="line">    &#123;&#123; wtf.quick_form(form) &#125;&#125;</span><br><span class="line">    <span class="tag">&lt;<span class="name">br</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span>&gt;</span>Forgot your password? <span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">"&#123;&#123; url_for('auth.password_reset_request') &#125;&#125;"</span>&gt;</span>Click here to reset it<span class="tag">&lt;/<span class="name">a</span>&gt;</span>.<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span>&gt;</span>New user? <span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">"&#123;&#123; url_for('auth.register') &#125;&#125;"</span>&gt;</span>Click here to register<span class="tag">&lt;/<span class="name">a</span>&gt;</span>.<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">&#123;% endblock %&#125;</span><br></pre></td></tr></table></figure>
<h2 id="app-auth-views-py-Sign-Out-route-用户登出-1"><a href="#app-auth-views-py-Sign-Out-route-用户登出-1" class="headerlink" title="app/auth/views.py: Sign Out route 用户登出 1"></a>app/auth/views.py: Sign Out route 用户登出 1</h2><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> flask_login <span class="keyword">import</span> logout_user, login_required</span><br><span class="line"></span><br><span class="line"><span class="meta">@auth.route('/login', methods=['GET', 'POST'])</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">login</span><span class="params">()</span>:</span></span><br><span class="line">    form = LoginForm()</span><br><span class="line">    <span class="keyword">if</span> form.validate_on_submit():</span><br><span class="line">        user = User.query.filter_by(email=form.email.data).first()</span><br><span class="line">        <span class="keyword">if</span> user <span class="keyword">is</span> <span class="keyword">not</span> <span class="keyword">None</span> <span class="keyword">and</span> user.verify_password(form.password.data):</span><br><span class="line">            login_user(user, form.remember_me.data)</span><br><span class="line">            next = request.args.get(<span class="string">'next'</span>)</span><br><span class="line">            <span class="keyword">if</span> next <span class="keyword">is</span> <span class="keyword">None</span> <span class="keyword">or</span> <span class="keyword">not</span> next.startswith(<span class="string">'/'</span>):</span><br><span class="line">                next = url_for(<span class="string">'main.index'</span>)</span><br><span class="line">            <span class="keyword">return</span> redirect(next)</span><br><span class="line">        flash(<span class="string">'Invalid username or password.'</span>)</span><br><span class="line">    <span class="keyword">return</span> render_template(<span class="string">'auth/login.html'</span>, form=form)</span><br></pre></td></tr></table></figure>
<h2 id="app-templates-index-html-Greet-the-logged-in-user-2"><a href="#app-templates-index-html-Greet-the-logged-in-user-2" class="headerlink" title="app/templates/index.html: Greet the logged-in user 2"></a>app/templates/index.html: Greet the logged-in user 2</h2><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">(venv) $ flask shell</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>u = User(email=<span class="string">'john@example.com'</span>, username=<span class="string">'john'</span>, password=<span class="string">'cat'</span>)</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>db.session.add(u)</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>db.session.commit()</span><br></pre></td></tr></table></figure>
<h2 id="app-auth-forms-py-User-registration-form-新用户注册"><a href="#app-auth-forms-py-User-registration-form-新用户注册" class="headerlink" title="app/auth/forms.py: User registration form 新用户注册"></a>app/auth/forms.py: User registration form 新用户注册</h2><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> flask <span class="keyword">import</span> render_template, redirect, request, url_for, flash</span><br><span class="line"><span class="keyword">from</span> flask_login <span class="keyword">import</span> login_user, logout_user, login_required, \</span><br><span class="line">    current_user</span><br><span class="line"><span class="keyword">from</span> . <span class="keyword">import</span> auth</span><br><span class="line"><span class="keyword">from</span> .. <span class="keyword">import</span> db</span><br><span class="line"><span class="keyword">from</span> ..models <span class="keyword">import</span> User</span><br><span class="line"><span class="keyword">from</span> ..email <span class="keyword">import</span> send_email</span><br><span class="line"><span class="keyword">from</span> .forms <span class="keyword">import</span> LoginForm, RegistrationForm, ChangePasswordForm,\</span><br><span class="line">    PasswordResetRequestForm, PasswordResetForm, ChangeEmailForm</span><br></pre></td></tr></table></figure>
<h2 id="app-auth-forms-py-User-registration-form-1"><a href="#app-auth-forms-py-User-registration-form-1" class="headerlink" title="app/auth/forms.py: User registration form 1"></a>app/auth/forms.py: User registration form 1</h2><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> flask <span class="keyword">import</span> render_template, redirect, request, url_for, flash</span><br><span class="line"><span class="keyword">from</span> flask_login <span class="keyword">import</span> login_user, logout_user, login_required, \</span><br><span class="line">    current_user</span><br><span class="line"><span class="keyword">from</span> . <span class="keyword">import</span> auth</span><br><span class="line"><span class="keyword">from</span> .. <span class="keyword">import</span> db</span><br><span class="line"><span class="keyword">from</span> ..models <span class="keyword">import</span> User</span><br><span class="line"><span class="keyword">from</span> ..email <span class="keyword">import</span> send_email</span><br><span class="line"><span class="keyword">from</span> .forms <span class="keyword">import</span> LoginForm, RegistrationForm, ChangePasswordForm,\</span><br><span class="line">    PasswordResetRequestForm, PasswordResetForm, ChangeEmailForm</span><br><span class="line"></span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">RegistrationForm</span><span class="params">(FlaskForm)</span>:</span></span><br><span class="line">    email = StringField(<span class="string">'Email'</span>, validators=[DataRequired(), Length(<span class="number">1</span>, <span class="number">64</span>),</span><br><span class="line">                                             Email()])</span><br><span class="line">    username = StringField(<span class="string">'Username'</span>, validators=[</span><br><span class="line">        DataRequired(), Length(<span class="number">1</span>, <span class="number">64</span>),</span><br><span class="line">        Regexp(<span class="string">'^[A-Za-z][A-Za-z0-9_.]*$'</span>, <span class="number">0</span>,</span><br><span class="line">               <span class="string">'Usernames must have only letters, numbers, dots or '</span></span><br><span class="line">               <span class="string">'underscores'</span>)])</span><br><span class="line">    password = PasswordField(<span class="string">'Password'</span>, validators=[</span><br><span class="line">        DataRequired(), EqualTo(<span class="string">'password2'</span>, message=<span class="string">'Passwords must match.'</span>)])</span><br><span class="line">    password2 = PasswordField(<span class="string">'Confirm password'</span>, validators=[DataRequired()])</span><br><span class="line">    submit = SubmitField(<span class="string">'Register'</span>)</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">validate_email</span><span class="params">(self, field)</span>:</span></span><br><span class="line">        <span class="keyword">if</span> User.query.filter_by(email=field.data).first():</span><br><span class="line">            <span class="keyword">raise</span> ValidationError(<span class="string">'Email already registered.'</span>)</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">validate_username</span><span class="params">(self, field)</span>:</span></span><br><span class="line">        <span class="keyword">if</span> User.query.filter_by(username=field.data).first():</span><br><span class="line">            <span class="keyword">raise</span> ValidationError(<span class="string">'Username already in use.'</span>)</span><br></pre></td></tr></table></figure>
<h2 id="app-auth-views-py-User-registration-route-注册新用户"><a href="#app-auth-views-py-User-registration-route-注册新用户" class="headerlink" title="app/auth/views.py: User registration route 注册新用户"></a>app/auth/views.py: User registration route 注册新用户</h2><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"></span><br><span class="line">@auth.route(&apos;/register&apos;, methods=[&apos;GET&apos;, &apos;POST&apos;])</span><br><span class="line">def register():</span><br><span class="line">    form = RegistrationForm()</span><br><span class="line">    if form.validate_on_submit():</span><br><span class="line">        user = User(email=form.email.data,</span><br><span class="line">                    username=form.username.data,</span><br><span class="line">                    password=form.password.data)</span><br><span class="line">        db.session.add(user)</span><br><span class="line">        db.session.commit()</span><br><span class="line">        token = user.generate_confirmation_token()</span><br><span class="line">        send_email(user.email, &apos;Confirm Your Account&apos;,</span><br><span class="line">                   &apos;auth/email/confirm&apos;, user=user, token=token)</span><br><span class="line">        flash(&apos;A confirmation email has been sent to you by email.&apos;)</span><br><span class="line">        return redirect(url_for(&apos;auth.login&apos;))</span><br><span class="line">    return render_template(&apos;auth/register.html&apos;, form=form)</span><br></pre></td></tr></table></figure>
<h1 id="用户权限"><a href="#用户权限" class="headerlink" title="用户权限"></a>用户权限</h1><h2 id="app-models-py-Role-permissions-1"><a href="#app-models-py-Role-permissions-1" class="headerlink" title="app/models.py: Role permissions 1"></a>app/models.py: Role permissions 1</h2><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Role</span><span class="params">(db.Model)</span>:</span></span><br><span class="line">    __tablename__ = <span class="string">'roles'</span></span><br><span class="line">    id = db.Column(db.Integer, primary_key=<span class="keyword">True</span>)</span><br><span class="line">    name = db.Column(db.String(<span class="number">64</span>), unique=<span class="keyword">True</span>)</span><br><span class="line">    default = db.Column(db.Boolean, default=<span class="keyword">False</span>, index=<span class="keyword">True</span>)</span><br><span class="line">    permissions = db.Column(db.Integer)</span><br><span class="line">    users = db.relationship(<span class="string">'User'</span>, backref=<span class="string">'role'</span>, lazy=<span class="string">'dynamic'</span>)</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, **kwargs)</span>:</span></span><br><span class="line">        super(Role, self).__init__(**kwargs)</span><br><span class="line">        <span class="keyword">if</span> self.permissions <span class="keyword">is</span> <span class="keyword">None</span>:</span><br><span class="line">            self.permissions = <span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="meta">    @staticmethod</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">insert_roles</span><span class="params">()</span>:</span></span><br><span class="line">        roles = &#123;</span><br><span class="line">            <span class="string">'User'</span>: [Permission.FOLLOW, Permission.COMMENT, Permission.WRITE],</span><br><span class="line">            <span class="string">'Moderator'</span>: [Permission.FOLLOW, Permission.COMMENT,</span><br><span class="line">                          Permission.WRITE, Permission.MODERATE],</span><br><span class="line">            <span class="string">'Administrator'</span>: [Permission.FOLLOW, Permission.COMMENT,</span><br><span class="line">                              Permission.WRITE, Permission.MODERATE,</span><br><span class="line">                              Permission.ADMIN],</span><br><span class="line">        &#125;</span><br><span class="line">        default_role = <span class="string">'User'</span></span><br><span class="line">        <span class="keyword">for</span> r <span class="keyword">in</span> roles:</span><br><span class="line">            role = Role.query.filter_by(name=r).first()</span><br><span class="line">            <span class="keyword">if</span> role <span class="keyword">is</span> <span class="keyword">None</span>:</span><br><span class="line">                role = Role(name=r)</span><br><span class="line">            role.reset_permissions()</span><br><span class="line">            <span class="keyword">for</span> perm <span class="keyword">in</span> roles[r]:</span><br><span class="line">                role.add_permission(perm)</span><br><span class="line">            role.default = (role.name == default_role)</span><br><span class="line">            db.session.add(role)</span><br><span class="line">        db.session.commit()</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">add_permission</span><span class="params">(self, perm)</span>:</span></span><br><span class="line">        <span class="keyword">if</span> <span class="keyword">not</span> self.has_permission(perm):</span><br><span class="line">            self.permissions += perm</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">remove_permission</span><span class="params">(self, perm)</span>:</span></span><br><span class="line">        <span class="keyword">if</span> self.has_permission(perm):</span><br><span class="line">            self.permissions -= perm</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">reset_permissions</span><span class="params">(self)</span>:</span></span><br><span class="line">        self.permissions = <span class="number">0</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">has_permission</span><span class="params">(self, perm)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> self.permissions &amp; perm == perm</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__repr__</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> <span class="string">'&lt;Role %r&gt;'</span> % self.name</span><br></pre></td></tr></table></figure>
<h2 id="app-models-py-Permission-constants-2"><a href="#app-models-py-Permission-constants-2" class="headerlink" title="app/models.py: Permission constants 2"></a>app/models.py: Permission constants 2</h2><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Permission</span>:</span></span><br><span class="line">    FOLLOW = <span class="number">1</span></span><br><span class="line">    COMMENT = <span class="number">2</span></span><br><span class="line">    WRITE = <span class="number">4</span></span><br><span class="line">    MODERATE = <span class="number">8</span></span><br><span class="line">    ADMIN = <span class="number">16</span></span><br></pre></td></tr></table></figure>
<h2 id="app-models-py-Permission-management-in-the-Role-model-3"><a href="#app-models-py-Permission-management-in-the-Role-model-3" class="headerlink" title="app/models.py: Permission management in the Role model 3"></a>app/models.py: Permission management in the Role model 3</h2><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Role</span><span class="params">(db.Model)</span>:</span></span><br><span class="line">    <span class="comment"># ...    </span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">add_permission</span><span class="params">(self, perm)</span>:</span></span><br><span class="line">        <span class="keyword">if</span> <span class="keyword">not</span> self.has_permission(perm):</span><br><span class="line">            self.permissions += perm    </span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">remove_permission</span><span class="params">(self, perm)</span>:</span> </span><br><span class="line">        <span class="keyword">if</span> self.has_permission(perm):</span><br><span class="line">            self.permissions -= perm</span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">reset_permissions</span><span class="params">(self)</span>:</span></span><br><span class="line">        self.permissions = <span class="number">0</span> </span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">has_permission</span><span class="params">(self, perm)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> self.permissions &amp; perm == perm</span><br></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">(venv) $ flask shell</span><br><span class="line">&gt;&gt;&gt; r = Role(name=<span class="string">'User'</span>)</span><br><span class="line">&gt;&gt;&gt; r.add_permission(Permission.FOLLOW)</span><br><span class="line">&gt;&gt;&gt; r.add_permission(Permission.WRITE)</span><br><span class="line">&gt;&gt;&gt; r.has_permission(Permission.FOLLOW)</span><br><span class="line">True</span><br><span class="line">&gt;&gt;&gt; r.has_permission(Permission.ADMIN)</span><br><span class="line">False</span><br><span class="line">&gt;&gt;&gt; r.reset_permissions()</span><br><span class="line">&gt;&gt;&gt; r.has_permission(Permission.FOLLOW)</span><br><span class="line">False</span><br></pre></td></tr></table></figure>
<h2 id="app-models-py-Create-roles-in-the-database-3"><a href="#app-models-py-Create-roles-in-the-database-3" class="headerlink" title="app/models.py: Create roles in the database 3"></a>app/models.py: Create roles in the database 3</h2><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Role</span><span class="params">(db.Model)</span>:</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># ....</span></span><br><span class="line">    </span><br><span class="line"><span class="meta">    @staticmethod</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">insert_roles</span><span class="params">()</span>:</span></span><br><span class="line">        roles = &#123;</span><br><span class="line">            <span class="string">'User'</span>: [Permission.FOLLOW, Permission.COMMENT, Permission.WRITE],</span><br><span class="line">            <span class="string">'Moderator'</span>: [Permission.FOLLOW, Permission.COMMENT,</span><br><span class="line">                          Permission.WRITE, Permission.MODERATE],</span><br><span class="line">            <span class="string">'Administrator'</span>: [Permission.FOLLOW, Permission.COMMENT,</span><br><span class="line">                              Permission.WRITE, Permission.MODERATE,</span><br><span class="line">                              Permission.ADMIN],</span><br><span class="line">        &#125;</span><br><span class="line">        default_role = <span class="string">'User'</span></span><br><span class="line">        <span class="keyword">for</span> r <span class="keyword">in</span> roles:</span><br><span class="line">            role = Role.query.filter_by(name=r).first()</span><br><span class="line">            <span class="keyword">if</span> role <span class="keyword">is</span> <span class="keyword">None</span>:</span><br><span class="line">                role = Role(name=r)</span><br><span class="line">            role.reset_permissions()</span><br><span class="line">            <span class="keyword">for</span> perm <span class="keyword">in</span> roles[r]:</span><br><span class="line">                role.add_permission(perm)</span><br><span class="line">            role.default = (role.name == default_role)</span><br><span class="line">            db.session.add(role)</span><br><span class="line">        db.session.commit()</span><br></pre></td></tr></table></figure>
<h2 id="app-models-py-Define-a-default-role-for-users-权限分配"><a href="#app-models-py-Define-a-default-role-for-users-权限分配" class="headerlink" title="app/models.py: Define a default role for users 权限分配"></a>app/models.py: Define a default role for users 权限分配</h2><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">User</span><span class="params">(UserMixin, db.Model)</span>:</span></span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, **kwargs)</span>:</span></span><br><span class="line">        super(User, self).__init__(**kwargs)</span><br><span class="line">        <span class="keyword">if</span> self.role <span class="keyword">is</span> <span class="keyword">None</span>:</span><br><span class="line">            <span class="keyword">if</span> self.email == current_app.config[<span class="string">'FLASKY_ADMIN'</span>]:</span><br><span class="line">                self.role = Role.query.filter_by(name=<span class="string">'Administrator'</span>).first()</span><br><span class="line">            <span class="keyword">if</span> self.role <span class="keyword">is</span> <span class="keyword">None</span>:</span><br><span class="line">                self.role = Role.query.filter_by(default=<span class="keyword">True</span>).first()</span><br></pre></td></tr></table></figure>
<h2 id="app-models-py-Evaluate-whether-a-user-has-a-given-permission-权限检查"><a href="#app-models-py-Evaluate-whether-a-user-has-a-given-permission-权限检查" class="headerlink" title="app/models.py: Evaluate whether a user has a given permission 权限检查"></a>app/models.py: Evaluate whether a user has a given permission 权限检查</h2><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">User</span><span class="params">(UserMixin, db.Model)</span>:</span></span><br><span class="line">    <span class="comment"># ...</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">can</span><span class="params">(self, perm)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> self.role <span class="keyword">is</span> <span class="keyword">not</span> <span class="keyword">None</span> <span class="keyword">and</span> self.role.has_permission(perm)</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">is_administrator</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> self.can(Permission.ADMIN)</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__repr__</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> <span class="string">'&lt;User %r&gt;'</span> % self.username</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AnonymousUser</span><span class="params">(AnonymousUserMixin)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">can</span><span class="params">(self, permissions)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">False</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">is_administrator</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">False</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">login_manager.anonymous_user = AnonymousUser</span><br></pre></td></tr></table></figure>
<h2 id="权限检查装饰器"><a href="#权限检查装饰器" class="headerlink" title="权限检查装饰器"></a>权限检查装饰器</h2><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> functools <span class="keyword">import</span> wraps</span><br><span class="line"><span class="keyword">from</span> flask <span class="keyword">import</span> abort</span><br><span class="line"><span class="keyword">from</span> flask_login <span class="keyword">import</span> current_user</span><br><span class="line"><span class="keyword">from</span> .models <span class="keyword">import</span> Permission</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">permission_required</span><span class="params">(permission)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">decorator</span><span class="params">(f)</span>:</span></span><br><span class="line"><span class="meta">        @wraps(f)</span></span><br><span class="line">        <span class="function"><span class="keyword">def</span> <span class="title">decorated_function</span><span class="params">(*args, **kwargs)</span>:</span></span><br><span class="line">            <span class="keyword">if</span> <span class="keyword">not</span> current_user.can(permission):</span><br><span class="line">                abort(<span class="number">403</span>)</span><br><span class="line">            <span class="keyword">return</span> f(*args, **kwargs)</span><br><span class="line">        <span class="keyword">return</span> decorated_function</span><br><span class="line">    <span class="keyword">return</span> decorator</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">admin_required</span><span class="params">(f)</span>:</span></span><br><span class="line">    <span class="keyword">return</span> permission_required(Permission.ADMIN)(f)</span><br></pre></td></tr></table></figure>
<h2 id="使用权限装饰器"><a href="#使用权限装饰器" class="headerlink" title="使用权限装饰器"></a>使用权限装饰器</h2><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> .decorators <span class="keyword">import</span> admin_required, permission_required</span><br><span class="line"></span><br><span class="line"><span class="meta">@main.route('/admin')</span></span><br><span class="line"><span class="meta">@login_required</span></span><br><span class="line"><span class="meta">@admin_required</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">for_admins_only</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">return</span> <span class="string">"For administrators!"</span></span><br><span class="line"></span><br><span class="line"><span class="meta">@main.route('/admin')</span></span><br><span class="line"><span class="meta">@login_required</span></span><br><span class="line"><span class="meta">@permission_required(Permission.MODERATE)</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">for_moderators_only</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">return</span> <span class="string">"For comment moderators!"</span></span><br></pre></td></tr></table></figure>
<h2 id="将权限检查添加到-全局上下文中"><a href="#将权限检查添加到-全局上下文中" class="headerlink" title="将权限检查添加到 全局上下文中"></a>将权限检查添加到 全局上下文中</h2><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="comment"># app/main/__init__.py: Adding the Permission class to the template context</span></span><br><span class="line"><span class="meta">@main.app_context_processor</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">inject_permissions</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">return</span> dict(Permission=Permission)</span><br></pre></td></tr></table></figure>
<h2 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h2><p>tests/test_user_model.py: Unit tests for roles and permissions</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> unittest</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"><span class="keyword">from</span> app <span class="keyword">import</span> create_app, db</span><br><span class="line"><span class="keyword">from</span> app.models <span class="keyword">import</span> User, AnonymousUser, Role, Permission</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">UserModelTestCase</span><span class="params">(unittest.TestCase)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">setUp</span><span class="params">(self)</span>:</span></span><br><span class="line">        self.app = create_app(<span class="string">'testing'</span>)</span><br><span class="line">        self.app_context = self.app.app_context()</span><br><span class="line">        self.app_context.push()</span><br><span class="line">        db.create_all()</span><br><span class="line">        Role.insert_roles()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">test_user_role</span><span class="params">(self)</span>:</span></span><br><span class="line">        u = User(email=<span class="string">'john@example.com'</span>, password=<span class="string">'cat'</span>)</span><br><span class="line">        self.assertTrue(u.can(Permission.FOLLOW))</span><br><span class="line">        self.assertTrue(u.can(Permission.COMMENT))</span><br><span class="line">        self.assertTrue(u.can(Permission.WRITE))</span><br><span class="line">        self.assertFalse(u.can(Permission.MODERATE))</span><br><span class="line">        self.assertFalse(u.can(Permission.ADMIN))</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">test_moderator_role</span><span class="params">(self)</span>:</span></span><br><span class="line">        r = Role.query.filter_by(name=<span class="string">'Moderator'</span>).first()</span><br><span class="line">        u = User(email=<span class="string">'john@example.com'</span>, password=<span class="string">'cat'</span>, role=r)</span><br><span class="line">        self.assertTrue(u.can(Permission.FOLLOW))</span><br><span class="line">        self.assertTrue(u.can(Permission.COMMENT))</span><br><span class="line">        self.assertTrue(u.can(Permission.WRITE))</span><br><span class="line">        self.assertTrue(u.can(Permission.MODERATE))</span><br><span class="line">        self.assertFalse(u.can(Permission.ADMIN))</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">test_administrator_role</span><span class="params">(self)</span>:</span></span><br><span class="line">        r = Role.query.filter_by(name=<span class="string">'Administrator'</span>).first()</span><br><span class="line">        u = User(email=<span class="string">'john@example.com'</span>, password=<span class="string">'cat'</span>, role=r)</span><br><span class="line">        self.assertTrue(u.can(Permission.FOLLOW))</span><br><span class="line">        self.assertTrue(u.can(Permission.COMMENT))</span><br><span class="line">        self.assertTrue(u.can(Permission.WRITE))</span><br><span class="line">        self.assertTrue(u.can(Permission.MODERATE))</span><br><span class="line">        self.assertTrue(u.can(Permission.ADMIN))</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">test_anonymous_user</span><span class="params">(self)</span>:</span></span><br><span class="line">        u = AnonymousUser()</span><br><span class="line">        self.assertFalse(u.can(Permission.FOLLOW))</span><br><span class="line">        self.assertFalse(u.can(Permission.COMMENT))</span><br><span class="line">        self.assertFalse(u.can(Permission.WRITE))</span><br><span class="line">        self.assertFalse(u.can(Permission.MODERATE))</span><br><span class="line">        self.assertFalse(u.can(Permission.ADMIN))</span><br></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">(venv) $ flask shell</span><br><span class="line">&gt;&gt;&gt; Role.insert_roles()</span><br><span class="line">&gt;&gt;&gt; Role.query.all()</span><br><span class="line">[&lt;Role <span class="string">'Administrator'</span>&gt;, &lt;Role <span class="string">'User'</span>&gt;, &lt;Role <span class="string">'Moderator'</span>&gt;]</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">(venv) $ flask shell</span><br><span class="line">&gt;&gt;&gt; admin_role = Role.query.filter_by(name=<span class="string">'Administrator'</span>).first()</span><br><span class="line">&gt;&gt;&gt; default_role = Role.query.filter_by(default=True).first()</span><br><span class="line">&gt;&gt;&gt; <span class="keyword">for</span> u <span class="keyword">in</span> User.query.all():</span><br><span class="line">...     <span class="keyword">if</span> u.role is None:</span><br><span class="line">...         <span class="keyword">if</span> u.email == app.config[<span class="string">'FLASKY_ADMIN'</span>]:</span><br><span class="line">...             u.role = admin_role</span><br><span class="line">...         <span class="keyword">else</span>:.</span><br><span class="line">..             u.role = default_role</span><br><span class="line">...</span><br><span class="line">&gt;&gt;&gt; db.session.commit()</span><br></pre></td></tr></table></figure>

        </div>

        <blockquote class="post-copyright">
    <div class="content">
        
<span class="post-time">
    最后更新时间：<time datetime="2019-02-22T05:28:07.839Z" itemprop="dateUpdated">2019-02-22 13:28:07</time>
</span><br>


        
        <a href="/2018/04/18/55-flask使用总结2/" target="_blank" rel="external">http://zhourudong.cn/2018/04/18/55-flask使用总结2/</a>
        
    </div>
    <footer>
        <a href="http://zhourudong.cn">
            <img src="/img/avatar.png" alt="cucy">
            cucy
        </a>
    </footer>
</blockquote>

        
<div class="page-reward">
    <a id="rewardBtn" href="javascript:;" class="page-reward-btn waves-effect waves-circle waves-light">赏</a>
</div>



        <div class="post-footer">
            
	<ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/flask/">flask</a></li></ul>


            
<div class="page-share-wrap">
    

<div class="page-share" id="pageShare">
    <ul class="reset share-icons">
      <li>
        <a class="weibo share-sns" target="_blank" href="http://service.weibo.com/share/share.php?url=http://zhourudong.cn/2018/04/18/55-flask使用总结2/&title=《flask使用总结2》 — Cucy的博客&pic=http://zhourudong.cn/img/avatar.png" data-title="微博">
          <i class="icon icon-weibo"></i>
        </a>
      </li>
      <li>
        <a class="weixin share-sns wxFab" href="javascript:;" data-title="微信">
          <i class="icon icon-weixin"></i>
        </a>
      </li>
      <li>
        <a class="qq share-sns" target="_blank" href="http://connect.qq.com/widget/shareqq/index.html?url=http://zhourudong.cn/2018/04/18/55-flask使用总结2/&title=《flask使用总结2》 — Cucy的博客&source=" data-title=" QQ">
          <i class="icon icon-qq"></i>
        </a>
      </li>
      <li>
        <a class="facebook share-sns" target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=http://zhourudong.cn/2018/04/18/55-flask使用总结2/" data-title=" Facebook">
          <i class="icon icon-facebook"></i>
        </a>
      </li>
      <li>
        <a class="twitter share-sns" target="_blank" href="https://twitter.com/intent/tweet?text=《flask使用总结2》 — Cucy的博客&url=http://zhourudong.cn/2018/04/18/55-flask使用总结2/&via=http://zhourudong.cn" data-title=" Twitter">
          <i class="icon icon-twitter"></i>
        </a>
      </li>
      <li>
        <a class="google share-sns" target="_blank" href="https://plus.google.com/share?url=http://zhourudong.cn/2018/04/18/55-flask使用总结2/" data-title=" Google+">
          <i class="icon icon-google-plus"></i>
        </a>
      </li>
    </ul>
 </div>



    <a href="javascript:;" id="shareFab" class="page-share-fab waves-effect waves-circle">
        <i class="icon icon-share-alt icon-lg"></i>
    </a>
</div>



        </div>
    </div>

    
<nav class="post-nav flex-row flex-justify-between">
  
    <div class="waves-block waves-effect prev">
      <a href="/2018/04/23/56-html-css网站收藏/" id="post-prev" class="post-nav-link">
        <div class="tips"><i class="icon icon-angle-left icon-lg icon-pr"></i> Prev</div>
        <h4 class="title">html-css网站收藏</h4>
      </a>
    </div>
  

  
    <div class="waves-block waves-effect next">
      <a href="/2018/04/18/54-flask使用总结1/" id="post-next" class="post-nav-link">
        <div class="tips">Next <i class="icon icon-angle-right icon-lg icon-pl"></i></div>
        <h4 class="title">flask使用总结1</h4>
      </a>
    </div>
  
</nav>



    














</article>

<div id="reward" class="page-modal reward-lay">
    <a class="close" href="javascript:;"><i class="icon icon-close"></i></a>
    <h3 class="reward-title">
        <i class="icon icon-quote-left"></i>
        谢谢大爷~
        <i class="icon icon-quote-right"></i>
    </h3>
    <div class="reward-content">
        
        <div class="reward-code">
            <img id="rewardCode" src="/img/wechat.jpg" alt="打赏二维码">
        </div>
        
        <label class="reward-toggle">
            <input id="rewardToggle" type="checkbox" class="reward-toggle-check"
                data-wechat="/img/wechat.jpg" data-alipay="/img/alipay.jpg">
            <div class="reward-toggle-ctrol">
                <span class="reward-toggle-item wechat">微信</span>
                <span class="reward-toggle-label"></span>
                <span class="reward-toggle-item alipay">支付宝</span>
            </div>
        </label>
        
    </div>
</div>



</div>

        <footer class="footer">
    <div class="top">
        
<p>
    <span id="busuanzi_container_site_uv" style='display:none'>
        站点总访客数：<span id="busuanzi_value_site_uv"></span>
    </span>
    <span id="busuanzi_container_site_pv" style='display:none'>
        站点总访问量：<span id="busuanzi_value_site_pv"></span>
    </span>
</p>


        <p>
            
                <span><a href="/atom.xml" target="_blank" class="rss" title="rss"><i class="icon icon-lg icon-rss"></i></a></span>
            
            <span>博客内容遵循 <a rel="license" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh">知识共享 署名 - 非商业性 - 相同方式共享 4.0 国际协议</a></span>
        </p>
    </div>
    <div class="bottom">
        <p><span>cucy &copy; 2016 - 2021</span>
            <span>
                
                Power by <a href="http://hexo.io/" target="_blank">Hexo</a> Theme <a href="https://github.com/yscoder/hexo-theme-indigo" target="_blank">indigo</a>
            </span>
        </p>
    </div>
</footer>

    </main>
    <div class="mask" id="mask"></div>
<a href="javascript:;" id="gotop" class="waves-effect waves-circle waves-light"><span class="icon icon-lg icon-chevron-up"></span></a>



<div class="global-share" id="globalShare">
    <ul class="reset share-icons">
      <li>
        <a class="weibo share-sns" target="_blank" href="http://service.weibo.com/share/share.php?url=http://zhourudong.cn/2018/04/18/55-flask使用总结2/&title=《flask使用总结2》 — Cucy的博客&pic=http://zhourudong.cn/img/avatar.png" data-title="微博">
          <i class="icon icon-weibo"></i>
        </a>
      </li>
      <li>
        <a class="weixin share-sns wxFab" href="javascript:;" data-title="微信">
          <i class="icon icon-weixin"></i>
        </a>
      </li>
      <li>
        <a class="qq share-sns" target="_blank" href="http://connect.qq.com/widget/shareqq/index.html?url=http://zhourudong.cn/2018/04/18/55-flask使用总结2/&title=《flask使用总结2》 — Cucy的博客&source=" data-title=" QQ">
          <i class="icon icon-qq"></i>
        </a>
      </li>
      <li>
        <a class="facebook share-sns" target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=http://zhourudong.cn/2018/04/18/55-flask使用总结2/" data-title=" Facebook">
          <i class="icon icon-facebook"></i>
        </a>
      </li>
      <li>
        <a class="twitter share-sns" target="_blank" href="https://twitter.com/intent/tweet?text=《flask使用总结2》 — Cucy的博客&url=http://zhourudong.cn/2018/04/18/55-flask使用总结2/&via=http://zhourudong.cn" data-title=" Twitter">
          <i class="icon icon-twitter"></i>
        </a>
      </li>
      <li>
        <a class="google share-sns" target="_blank" href="https://plus.google.com/share?url=http://zhourudong.cn/2018/04/18/55-flask使用总结2/" data-title=" Google+">
          <i class="icon icon-google-plus"></i>
        </a>
      </li>
    </ul>
 </div>


<div class="page-modal wx-share" id="wxShare">
    <a class="close" href="javascript:;"><i class="icon icon-close"></i></a>
    <p>扫一扫，分享到微信</p>
    <img src="//api.qrserver.com/v1/create-qr-code/?data=http://zhourudong.cn/2018/04/18/55-flask使用总结2/" alt="微信分享二维码">
</div>




    <script src="//cdn.bootcss.com/node-waves/0.7.4/waves.min.js"></script>
<script>
var BLOG = { ROOT: '/', SHARE: true, REWARD: true };


</script>

<script src="/js/main.min.js?v=1.6.13"></script>


<div class="search-panel" id="search-panel">
    <ul class="search-result" id="search-result"></ul>
</div>
<template id="search-tpl">
<li class="item">
    <a href="{path}" class="waves-block waves-effect">
        <div class="title ellipsis" title="{title}">{title}</div>
        <div class="flex-row flex-middle">
            <div class="tags ellipsis">
                {tags}
            </div>
            <time class="flex-col time">{date}</time>
        </div>
    </a>
</li>
</template>

<script src="/js/search.min.js?v=1.6.13" async></script>






<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>



<script>
(function() {
    var OriginTitile = document.title, titleTime;
    document.addEventListener('visibilitychange', function() {
        if (document.hidden) {
            document.title = '死鬼去哪里了！';
            clearTimeout(titleTime);
        } else {
            document.title = '(つェ⊂)咦!又好了!';
            titleTime = setTimeout(function() {
                document.title = OriginTitile;
            },2000);
        }
    });
})();
</script>



</body>
</html>
